package model.impl;

import java.util.LinkedList;
import java.util.Queue;

import model.EMenuState;
import model.IinGame;

import org.newdawn.slick.Input;

import controller.impl.KeyPress;

import sharedGameLogic.enums.BattleDistance;
import sharedGameLogic.enums.BattleEvent;
import sharedGameLogic.enums.GameStatus;
import sharedGameLogic.gameData.BattleResult;
import sharedGameLogic.gameData.InitialPlayerStatus;
import sharedGameLogic.gameData.InitialStatus;
import sharedGameLogic.gameData.PlayerResult;


class InGameState implements IModelState, IinGame {
	
	private static final InGameState INSTANCE = new InGameState();
	
	private MenuItemHandler menuHandler;
	private boolean gameFinished;
	private boolean gameHasStarted;
	
	private int playerOneMaxHP;
	private int playerTwoMaxHP;
	private int playerOneMaxEnergy;
	private int playerTwoMaxEnergy;
	private int playerOneHealth;
	private int playerTwoHealth;
	private int playerOneEnergy;
	private int playerTwoEnergy;
	private String playerOneNick;
	private String playerTwoNick;
	private String playerOneCharacter;
	private String playerTwoCharacter;
	private BattleEvent playerOneAction;
	private BattleEvent playerTwoAction;
	private boolean playerOneActionSuccessful;
	private boolean playerTwoActionSuccessful;
	private BattleDistance distance;
	private GameStatus gameStatus;
	private String message;
	private boolean hasChanged;
	
	private boolean waitingForServerResponse;
	
	private InGameState() {
		menuHandler = new MenuItemHandler();
		reset();
	}

	public static InGameState getInstance() {
		return INSTANCE;
	}
	
	@Override
	public void reset() {
		menuHandler.reset();
		waitingForServerResponse = false;
		hasChanged = false;
		gameFinished = false;
		gameHasStarted = false;
		playerOneAction = null;
		playerTwoAction = null;
	}
	
	@Override
	public void addStateListener(StateListener listener) {
		// TODO Auto-generated method stub

	}
	
	//This method is supposed to be used only in the menu-state
	@Override
	public void viewCharacterSelection() {
		
	}

	//This method is supposed to be used only in the menu-state
	@Override
	public void viewConnecting() {
		
	}

	//This method is supposed to be used only in the menu-state
	@Override
	public void viewMainMenu() {
		
	}

	//This method is supposed to be used only in the menu-state
	@Override
	public void viewSettings() {
		
	}

	@Override
	public EMenuState getEMenuState() {
		if (gameHasStarted) {
			return EMenuState.IN_GAME;
		}
		return EMenuState.CONNECTING;
	}

	@Override
	public void newInput(KeyPress keyPress) {
		int key = keyPress.getKey();
		
		if (key == Input.KEY_UP) {
			if (!gameFinished && gameHasStarted) {
				previousAlternative();
			}
		} else if (key == Input.KEY_DOWN) {
			if (!gameFinished && gameHasStarted) {
				nextAlternative();
			}
		} else if (key == Input.KEY_LEFT) {
			if (!gameFinished && gameHasStarted) {
				prevoiusMenu();
			}
		} else if (key == Input.KEY_ENTER) {
			if (!gameFinished && gameHasStarted) {
				fireAlternative();
			} else if (gameFinished) {
				Model.getInstance().gameFinished();
			}
		}
	}

	@Override
	public void newData(Object obj) {
		if (obj instanceof BattleResult) {
			BattleResult result = (BattleResult) obj;
			PlayerResult playerOne = result.getFirstPlayer();
			PlayerResult playerTwo = result.getSecondPlayer();
			
			gameStatus = result.getGameStatus();
			
			switch (result.getGameStatus()) {
			case FIGHT_GOING_ON:
				message = "Choose an action";
				gameFinished = false;
				break;
			case PLAYER_ONE_WON:
				message = playerOneNick + " wins!";
				gameFinished = true;
				break;
			case PLAYER_TWO_WON:
				message = playerTwoNick + " wins!";
				gameFinished = true;
				break;
			case DRAW:
				message = "Draw!";
				gameFinished = true;
				break;
			}
			
			playerOneEnergy = playerOne.getNewEnergy();
			playerOneHealth = playerOne.getNewHealth();
			playerOneAction = playerOne.getActionType();
			
			playerTwoEnergy = playerTwo.getNewEnergy();
			playerTwoHealth = playerTwo.getNewHealth();
			playerTwoAction = playerTwo.getActionType();
			
			distance = result.getCurrentDistance();
			waitingForServerResponse = false;
			hasChanged = true;
		} else if (obj instanceof InitialStatus) {
			InitialStatus status = (InitialStatus) obj;
			InitialPlayerStatus playerOneStatus = status.getPlayerOneStatus();
			InitialPlayerStatus playerTwoStatus = status.getPlayerTwoStatus();
			playerOneMaxEnergy = playerOneStatus.getMaxEnergy();
			playerOneEnergy = playerOneMaxEnergy;
			playerOneMaxHP = playerOneStatus.getMaxHealth();
			playerOneHealth = playerOneMaxHP;
			playerOneNick = playerOneStatus.getPlayerName();
			playerOneCharacter = playerOneStatus.getCharacterName();
			
			playerTwoMaxEnergy = playerTwoStatus.getMaxEnergy();
			playerTwoEnergy = playerTwoMaxEnergy;
			playerTwoMaxHP = playerTwoStatus.getMaxHealth();
			playerTwoHealth = playerTwoMaxHP;
			playerTwoNick = playerTwoStatus.getPlayerName();
			playerTwoCharacter = playerTwoStatus.getCharacterName();
			
			distance = status.getDistance();
			hasChanged = true;
		}
	}
	
	private void nextAlternative() {
		menuHandler.nextMenuItem();
	}
	
	private void previousAlternative() {
		menuHandler.previousMenuItem();
	}
	
	private void fireAlternative() {
		if (!waitingForServerResponse) {
			if (menuHandler.getMenuPosition().length == 3) {
				if (menuHandler.getCurrentAction() != null) {
					System.out.println("Current action: " + menuHandler.getCurrentAction().toString());
					Queue<BattleEvent> actions = new LinkedList<BattleEvent>();
					actions.add(menuHandler.getCurrentAction());
					Model.getInstance().newObject(actions);
					message = "Waiting for the opponent's action";
					waitingForServerResponse = true;
				}
			}
			menuHandler.goIntoSubMenu();
		}
		
	}
	
	private void prevoiusMenu() {
		menuHandler.goBackToSuperMenu();
	}

	@Override
	public int[] getMarkedMenuItem() {
		return menuHandler.getMenuPosition();
	}

	@Override
	public BattleEvent getPlayerOneAction() {
		return playerOneAction;
	}

	@Override
	public BattleEvent getPlayerTwoAction() {
		return playerTwoAction;
	}

	@Override
	public boolean hasChanged() {
		if (hasChanged) {
			hasChanged = false;
			return true;
		}
		return false;
	}

	@Override
	public double getPlayerOneEnergy() {
		if (playerOneMaxEnergy != 0) {
			return (double)playerOneEnergy / playerOneMaxEnergy;
		}
		return 0;
	}

	@Override
	public double getPlayerOneHealth() {
		if (playerOneMaxHP != 0) {
			return (double)playerOneHealth / playerOneMaxHP;
		}
		return 0;
	}

	@Override
	public double getPlayerTwoEnergy() {
		if (playerTwoMaxEnergy != 0) {
			return (double)playerTwoEnergy / playerTwoMaxEnergy;
		}
		return 0;
	}

	@Override
	public double getPlayerTwoHealth() {
		if (playerTwoMaxHP != 0) {
			return (double)playerTwoHealth / playerTwoMaxHP;
		}
		return 0;
	}

	@Override
	public BattleDistance getDistance() {
		return distance;
	}

	@Override
	public String getPlayerOneNick() {
		return playerOneNick;
	}

	@Override
	public String getPlayerTwoNick() {
		return playerTwoNick;
	}
	
	

	@Override
	public void startGame() {
		gameHasStarted = true;
		message = "Choose an action";
	}

	@Override
	public boolean isPlayerOneActionSuccessful() {
		return playerOneActionSuccessful;
	}

	@Override
	public boolean isPlayerTwoActionSuccessful() {
		return playerTwoActionSuccessful;
	}
	
	@Override
	public String getPlayerOneCharacterName() {
		return playerOneCharacter;
	}
	
	@Override
	public String getPlayerTwoCharacterName() {
		return playerTwoCharacter;
	}
	
	@Override
	public GameStatus getGameStatus() {
		return gameStatus;
	}
	
	@Override
	public String getMessage() {
		return message;
	}
}
